﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Threading;
using System.IO.MemoryMappedFiles;
using OpenHardwareMonitor.Hardware;

namespace RemoteHardwareMonitor
{
/// <summary>
    /// This class creates an XML document to provide structured access to the sensor data that IHardwareMonSrvce exposes. 
/// </summary>
    class SensorsToXML
    {
        SensorMap map;
        XmlWriter writer;
        MemoryMappedFile mmf;
        MemoryMappedViewStream mmvs;
        Dictionary<string, int> sensorMap;
        
        /// <summary>
        /// Create an instance that maps to a .NET memory mapped file (unused)
        /// </summary>
        /// <param name="Map">RemoteHardwareMonitor.SensorMap</param>
        /// <param name="Mmf">.NET Memory Mapped File</param>

        public SensorsToXML(SensorMap Map, MemoryMappedFile Mmf)
        {
            map = Map;
            mmf = Mmf;
        }

        /// <summary>
        /// Create an instance without passing a Memory Mapped File
        /// </summary>
        /// <param name="Map">RemoteHardwareMonitor.SensorMap</param>
        public SensorsToXML(SensorMap Map)
        {
            map = Map;
        }

        /// <summary>
        /// Map to memory-mapped xml document
        /// </summary>
        /// <param name="GPUs"></param>
        /// <param name="CPUs"></param>
        public void MapToFile(IHardware[] GPUs, IHardware[] CPUs)
        {
            try
            {
                mmvs = mmf.CreateViewStream();
                writer = XmlWriter.Create(mmvs);
              // writer = XmlWriter.Create("./testDoc.xml");

                writer.WriteStartDocument();
                writer.WriteStartElement("hardware");
                writer.WriteStartElement("GPUs");
                writer.WriteAttributeString("count", GPUs.Length.ToString());
                int hardwareIndex = 0;
                foreach (IHardware gpu in GPUs)
                {
                    sensorMap = map.GPUMap[hardwareIndex];

                    writer.WriteStartElement("GPU");
                    writer.WriteAttributeString("name", gpu.Name);
                    writer.WriteAttributeString("index", hardwareIndex.ToString());
                    writer.WriteStartElement("sensors");
                    foreach (KeyValuePair<string, int> kvp in sensorMap)
                    {
                        writer.WriteStartElement(kvp.Key.Replace(" ", "").Replace("#", ""));
                        writer.WriteElementString("Current", gpu.Sensors[kvp.Value].Value.ToString());
                        writer.WriteElementString("Max", gpu.Sensors[kvp.Value].Max.ToString());
                        writer.WriteEndElement();
                    }
                    writer.WriteEndElement();//sensors
                    writer.WriteEndElement();//GPU
                    hardwareIndex++;

                }
                writer.WriteEndElement(); // GPUs

                writer.WriteStartElement("CPUs");
                writer.WriteAttributeString("count", CPUs.Length.ToString());
                hardwareIndex = 0;

                foreach (IHardware cpu in CPUs)
                {
                    sensorMap = map.CPUMap[hardwareIndex];

                    writer.WriteStartElement("CPU");
                    writer.WriteAttributeString("name", cpu.Name);
                    writer.WriteAttributeString("index", hardwareIndex.ToString());
                    writer.WriteStartElement("sensors");
                    foreach (KeyValuePair<string, int> kvp in sensorMap)
                    {
                        writer.WriteStartElement(kvp.Key.Replace(" ","").Replace("#",""));
                        writer.WriteElementString("Current", cpu.Sensors[kvp.Value].Value.ToString());
                        writer.WriteElementString("Max", cpu.Sensors[kvp.Value].Max.ToString());
                        writer.WriteEndElement();
                    }
                    writer.WriteEndElement();//sensors
                    writer.WriteEndElement();//CPU
                    hardwareIndex++;


                }

                writer.WriteEndElement();//CPUs
                writer.WriteEndElement(); //hardware
                writer.WriteEndDocument();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
            finally
            {
                writer.Flush();
                writer.Close();

                mmvs.Close();
            }

           
        }

        /// <summary>
        ///  Map to an XML Document object.
        /// </summary>
        /// <param name="GPUs"></param>
        /// <param name="CPUs"></param>
        /// <returns></returns>
        public XmlDocument MapToDocument(IHardware[] GPUs, IHardware[] CPUs)
        {
            XmlDocument xdoc = new XmlDocument();
            using (XmlWriter writer = xdoc.CreateNavigator().AppendChild())
            {
                try
                {
                    writer.WriteStartDocument();
                    writer.WriteStartElement("hardware");
                    writer.WriteStartElement("GPUs");
                    writer.WriteAttributeString("count", GPUs.Length.ToString());
                    int hardwareIndex = 0;
                    foreach (IHardware gpu in GPUs)
                    {
                        sensorMap = map.GPUMap[hardwareIndex];

                        writer.WriteStartElement("GPU");
                        writer.WriteAttributeString("name", gpu.Name);
                        writer.WriteAttributeString("index", hardwareIndex.ToString());
                        writer.WriteStartElement("sensors");
                        foreach (KeyValuePair<string, int> kvp in sensorMap)
                        {
                            writer.WriteStartElement(kvp.Key.Replace(" ", "").Replace("#", ""));
                            writer.WriteElementString("Current", gpu.Sensors[kvp.Value].Value.ToString());
                            writer.WriteElementString("Max", gpu.Sensors[kvp.Value].Max.ToString());
                            writer.WriteEndElement();
                        }
                        writer.WriteEndElement();//sensors
                        writer.WriteEndElement();//GPU
                        hardwareIndex++;

                    }
                    writer.WriteEndElement(); // GPUs

                    writer.WriteStartElement("CPUs");
                    writer.WriteAttributeString("count", CPUs.Length.ToString());
                    hardwareIndex = 0;

                    foreach (IHardware cpu in CPUs)
                    {
                        sensorMap = map.CPUMap[hardwareIndex];

                        writer.WriteStartElement("CPU");
                        writer.WriteAttributeString("name", cpu.Name);
                        writer.WriteAttributeString("index", hardwareIndex.ToString());
                        writer.WriteStartElement("sensors");
                        foreach (KeyValuePair<string, int> kvp in sensorMap)
                        {
                            writer.WriteStartElement(kvp.Key.Replace(" ", "").Replace("#", ""));
                            writer.WriteElementString("Current", cpu.Sensors[kvp.Value].Value.ToString());
                            writer.WriteElementString("Max", cpu.Sensors[kvp.Value].Max.ToString());
                            writer.WriteEndElement();
                        }
                        writer.WriteEndElement();//sensors
                        writer.WriteEndElement();//CPU
                        hardwareIndex++;


                    }

                    writer.WriteEndElement();//CPUs
                    writer.WriteEndElement(); //hardware
                    writer.WriteEndDocument();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
                finally
                {
                    writer.Flush();
                    writer.Close();
                }
            }
            return xdoc;
        }
    }
}
